﻿/*
	Copyright 2009 Jason Nottingham

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.


    How to submit a patch:
    1. create or modify a test case (under 'tests') so that it fails to compile/link/run without 
       your change
    2. verify you have the latest sources (resync/merge)
    3. fix or add the missing functionality
    4. verify that your changes fixes the newly broken test case in #1 - it now builds and runs 
       C++ the same as the original C#
    5. create a Subversion-friendly diff or patch file of your changes (including the test cases)
    6. submit your patch at http://gonative.codeplex.com


*/

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;


namespace GoNative
{

    /// <summary>
    /// 
    /// </summary>
    internal class Globals
    {
        public static List<string> ClassVariables = new List<string>();
        public static List<string> GlobalVariables = new List<string>();
        public static List<string> MethodVariables = new List<string>();

        public static Stack<Dictionary<string, string>> VariablesInScope = new Stack<Dictionary<string, string>>();
        public static Dictionary<string, string> ManagedToUnmanagedLookup = new Dictionary<string, string>();

        public static string GoNativeTranslatorVersion = "0.0.1";
        public static string TargetPlatform = "win32";  // eventually support: win32, wince, qt

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string RemoveGunk(string s)
        {
            s = StripComments(s);
            s = s.Replace("\n", " ");
            s = s.Replace("\r", " ");
            s = s.Replace("\t", " ");
            s = s.Replace("    ", " ");
            s = s.Replace("   ", " ");
            s = s.Replace("  ", " ");
            s = s.Replace("  ", " ");
            return s.Trim();
        }

        /// <summary>
        /// we don't like to strip comments, but in this release if they are not 
        /// 1. in the code body
        /// 2. before the method they refer to 
        /// 3. before the first private/public variable in the class
        /// then we don't preserve them
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string StripComments(string s)
        {
            int i = s.IndexOf("//");

            while (i > -1)
            {
                int end = s.IndexOf("\n", i);
                if (end == -1)
                    break;
                s = s.Remove(i, end - i);
                i = s.IndexOf("//");
            }

            i = s.IndexOf("/*");
            while (i > -1)
            {
                int end = s.IndexOf("*/", i);
                if (end == -1)
                    break;
                end += 2;
                s = s.Remove(i, end - i);
                i = s.IndexOf("/*");
            }
            return s;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="find"></param>
        /// <returns></returns>
        public static string StringBefore(string s, string find)
        {
            int i = s.IndexOf(find);
            if (i > -1)
                s = s.Substring(0, i - 1);
            return s;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string HandleConsoleWriteStatement(string s)
        {
            string parameters = GetSubString(s, "(", ")", false).Trim();
            if ( string.IsNullOrEmpty(parameters))
                return s;
            int i = s.IndexOf("(");
            if ( i == -1 )
                return string.Empty;
            string before = s.Substring(0, i+1);
            i = s.LastIndexOf(")");
            if (i == -1)
                return string.Empty;
            string after = s.Substring(i);

            if (!parameters.StartsWith("string("))
            {
                bool singleString;
                parameters = HandleStringAddition(parameters, out singleString);
                if (!singleString)
                    s = before + parameters + after;
            }
            return s;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="singleString"></param>
        /// <returns></returns>
        private static string HandleStringAddition(string parameters, out bool singleString)
        {
            string[] p = ParseParameterList(parameters);

            if ((p.Length == 1) && (p[0].StartsWith("\"")))
            {
                // it is a single double-quoted string, we can leave
                // it as-is
                singleString = true;
            }
            else
            {
                singleString = false;
                StringBuilder sb = new StringBuilder();
                sb.Append(" string(" + p[0] + ") ");
                for (int i = 1; i < p.Length; i++)
                    sb.Append("+ " + p[i] + " ");
                parameters = sb.ToString();
            }
            return parameters;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private static string[] ParseParameterList(string parameters)
        {
            List<string> p = new List<string>();
            List<int> splitAt = new List<int>();

            // need to parse the parameters based on +, but ignore the
            // + if it occurs inside a string, and ignore quotes if they
            // are immediately after \"

            char[] chars = parameters.ToCharArray();
            bool ignoreNext = false;
            bool insideString = false;
            int i;
            splitAt.Add(0);
            for( i = 0; i < chars.Length; i++)
            {
                if ( chars[i] == '\\' )
                    ignoreNext = true;
                else
                {
                    if ( ignoreNext )
                        ignoreNext = false;
                    else
                    {
                        switch (chars[i])
                        {
                            case '"':
                                insideString = !insideString;
                                break;
                            case '+':
                                if ( !insideString )
                                    splitAt.Add(i+1);
                                break;
                        }
                    }
                }
            }

            if (splitAt.Count == 1)
            {
                p.Add(parameters);
            }
            else
            {
                int[] splits = splitAt.ToArray();
                for (i = 0; i < splits.Length - 1; i++)
                {
                    int length = splits[i + 1] - splits[i] - 1;
                    p.Add(parameters.Substring(splits[i], length).Trim());
                }
                p.Add(parameters.Substring(splits[splits.Length - 1]).Trim());
            }
            return p.ToArray();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ConvertArraysToLists(string s)
        {
            string indent = ReproduceLeadingTabs(s);
            string[] words = s.Replace("(", "( ").Replace(")", " )").Split(' ');

            string listName = "";
            int i;
            bool hasArrayInitialization = s.Contains("{");
            for (i = 0; i < words.Length; i++)
            {
                if (words[i].Contains("[]") && ( i < words.Length-1))
                {
                    listName = words[i + 1];
                    words[i] = string.Format("{0}List<{1}>", indent, words[i].Replace("[]", "").Replace("\t", ""));
                }
                if (hasArrayInitialization && words[i].Contains("="))
                {
                    words[i] = ";";
                    i++;
                    break;
                }
            }
            StringBuilder sb = new StringBuilder();
            int j;
            for (j = 0; j < i; j++)
                sb.Append(words[j] + " ");
            if (j < i)
                sb.Append(words[j]);

            if (hasArrayInitialization)
            {
                int equals = s.IndexOf("=");
                if (equals != -1)
                {
                    int open = s.IndexOf("{", equals);
                    if (open != -1)
                    {
                        int close = s.IndexOf("}", open);
                        if (close != -1)
                        {
                            string parameters = s.Substring(open + 1, close - open - 2);
                            string[] initializers = parameters.Split(',');
                            foreach (string initializer in initializers)
                                sb.Append("\n" + indent + listName + ".Add(" + initializer.Trim() + ");");
                        }
                    }
                }
            }
            s = sb.ToString();

            int toArray = s.IndexOf(".ToArray");
            if (toArray != -1)
            {
                s = s.Substring(0, toArray);
                s = s.Replace("=", "(") + ");";
                s = s.Replace(" (", "(").Replace("( ", "(");
            }

            return s;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string ReproduceLeadingTabs(string s)
        {
            StringBuilder tabs = new StringBuilder();
            for (int i = 0; i < s.Length; i++)
                if (s[i] == '\t')
                    tabs.Append("\t");
                else
                    break;
            return tabs.ToString();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="sourceLines"></param>
        /// <param name="sourceIndex"></param>
        /// <param name="enums"></param>
        /// <returns></returns>
        private static string ConvertForEach(string s, string[] sourceLines, ref int sourceIndex, Dictionary<string,string> enums)
        {
            char[] chars = s.ToCharArray();
            int spaceIndentation = 0;

            int tabIndentation = CountCharsAtStart(chars, '\t');
            if (tabIndentation == 0)
                spaceIndentation = CountCharsAtStart(chars, ' ');

            string indent = IndentationString(tabIndentation, spaceIndentation);
            string indented = indent + "\t";

            int first = s.IndexOf("(");
            int last = s.LastIndexOf(")");

            s = s.Substring(first + 1, last - first - 1);

            s = s.Replace("  ", " ").Trim();
            string[] words = s.Split(' ');

            string variableType = words[0];
            string variableName = words[1];

            int inKeyword = s.IndexOf(" in ");
            string collectionName = s.Substring(inKeyword + 4).Trim();

            if (variableType == "var")
            {
                string collectionType = LookUpVariableType(collectionName, null);
                int open = collectionType.IndexOf("<");
                int close = collectionType.IndexOf(">");
                if (open < close)
                    // it is a list (or ...) we want the type that comes between < and >
                    variableType = collectionType.Substring(open + 1, close - open - 1);
                else if (collectionType.Contains("[]")) // if is an array
                    variableType = collectionType.Replace("[]", "");
            }

            bool dictionary = variableType.Contains(",");

            if (dictionary)
            {
                string newType = GetSubString(variableType, "<", ">", false);
                if (!string.IsNullOrEmpty(newType))
                    variableType = newType;
            }

            string[] variableTypes = variableType.Split(',');
            string[] variableNames = new string[variableTypes.Length];

            int i;

            switch (variableTypes.Length)
            {
                case 1:
                    variableTypes[0] = variableTypes[0].Trim();
                    variableNames[0] = variableName;
                    break;
                case 2:
                    variableTypes[0] = variableTypes[0].Trim();
                    variableTypes[1] = variableTypes[1].Trim();
                    variableNames[0] = variableName + "Key";
                    variableNames[1] = variableName + "Value";
                    break;
                default:
                    Debug.Assert(false, "variableType.Length should always be 1 or 2");
                    break;
            }

            s = indent + "{\n";

            if (collectionName.Contains("."))
                s += RemapCollectionName(".", ref collectionName, indented, variableType);
            else if (collectionName.Contains("::"))
                s += RemapCollectionName("::", ref collectionName, indented, variableType);
            else
                collectionName += ".";

            StringBuilder sbBlock = new StringBuilder(s);

            for (i = 0; i < variableTypes.Length; i++)
                sbBlock.AppendFormat("{0}{1} {2};\n", indented, variableTypes[i], variableNames[i]);

            sbBlock.AppendFormat("{0}{1}start_iteration();\n{2}while( {3}get_next( ", 
                indented, collectionName, indented, collectionName);

            for (i = 0; i < variableTypes.Length; i++)
            {
                sbBlock.Append(variableNames[i]);
                if (i < variableTypes.Length - 1)
                    sbBlock.Append(", ");
            }
            sbBlock.Append(" ) )\n");

            s = sourceLines[sourceIndex++];
            if (dictionary)
                s = s.Replace(variableName + ".", variableName);
            if (s.TrimStart().StartsWith("{"))
            {
                sourceIndex--;
                // process the block of code
                while (!s.EndsWith("}")) // BUGBUG - will not handle nesting
                {
                    string nextLine = ProcessLine(sourceLines, ref sourceIndex, enums) + "\n";
                    if (string.IsNullOrEmpty(nextLine))
                        break;

                    if (dictionary)
                        nextLine = nextLine.Replace(variableName + ".", variableName);

                    sbBlock.AppendFormat("\t{0}", nextLine);
                    s = sourceLines[sourceIndex++];
                }
                sourceIndex--;
            }
            else
            {
                // process just the next line of code
                sourceIndex--;
                s = ProcessLine(sourceLines, ref sourceIndex, enums);
                if (dictionary)
                    s = s.Replace(variableName + ".", variableName);
                sbBlock.AppendFormat("\t{0}\n", s);
            }
            sbBlock.Append(indent + "}\n");
            return sbBlock.ToString();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="tabs"></param>
        /// <param name="spaces"></param>
        /// <returns></returns>
        private static string IndentationString(int tabs, int spaces)
        {
            StringBuilder sbIndent = new StringBuilder();
            int i;
            for (i = 0; i < tabs; i++)
                sbIndent.Append("\t");
            for (i = 0; i < spaces; i++)
                sbIndent.Append(" ");
            return sbIndent.ToString();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="chars"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        private static int CountCharsAtStart(char[] chars, char c)
        {
            int count = 0;
            while (chars[count] == c)
                count++;
            return count;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="toFind"></param>
        /// <param name="collectionName"></param>
        /// <param name="indent"></param>
        /// <param name="variableType"></param>
        /// <returns></returns>
        private static string RemapCollectionName(string toFind, ref string collectionName, string indent,
                                                  string variableType)
        {
            string oldName = collectionName;
            collectionName = RemoveParens(string.Format("{0}Collection", collectionName.Replace(toFind, "")));
            string answer = string.Format("{0}List<{1}> *{2} = {3};\n", indent, variableType, collectionName, oldName);
            collectionName += "->";
            return answer;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string RemoveParens(string s)
        {
            int start = s.IndexOf("(");
            while (start > -1)
            {
                int end = s.IndexOf(")", start);
                if (end == -1)
                    break;
                s = s.Remove(start, end - start + 1);
                start = s.IndexOf("(");
            }
            return s;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string AddImportantComment(string s)
        {
            return string.Format("// BUGBUG - {0}\r\n", s);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceLines"></param>
        /// <param name="sourceIndex"></param>
        /// <param name="enums"></param>
        /// <returns></returns>
        public static string ProcessLine(string[] sourceLines, ref int sourceIndex, Dictionary<string,string> enums)
        {
            int i;
            string s = sourceLines[sourceIndex].Replace("new[]", "");

            bool containsOpeningScope;  // outside of a string or comment
            bool containsClosingScope;  // outside of a string or comment
            bool containsBrackets;      // outside of a string or comment

            // handle window form timers/controls
            s = s.Replace("new System.Drawing.", "");

            string[] ignoreLinesContaining = { "= new System.",
                                               "= new Timer",
                                               ".Tick +="
                                             };
            foreach (string toIgnore in ignoreLinesContaining)
                if (s.Contains(toIgnore))
                    return string.Empty;

            string[] commentLinesContaining = {
                                                "= new System.EventHandler",
                                                "Application::Run",
                                                "menuStrip",  // menu strips not supported in this release
                                                "MenuItem",   // menu items  not supported in this release
                                                "this.AutoScaleMode"
                                              };

            foreach (string toComment in commentLinesContaining)
                if (s.Contains(toComment))
				{
					s = string.Format("//{0}", s);
					break;
				}

            s = PreprocessLine(s, out containsOpeningScope, out containsClosingScope, out containsBrackets, enums);

            // BUGBUG - need to make sure '{' does not appear inside a string (like in 'string.Format'
            // This will work as-is (assuming the '}' is on the same line), but does extra/unnecessary processing
            if (s.Contains("{"))
            {
                StringBuilder sb = new StringBuilder();
                for (i = sourceIndex; i < sourceLines.Length; i++)
                    sb.Append(sourceLines[i] + "\n");
                PushScopedVariables(sb.ToString());
            }
            if (s.Contains("}"))
                PopScopedVariables();

            if (s.Contains("<"))
                s = RemoveSpacesInsideBrackets(s);

            string[] words = s.Split(' ');

            if ((words.Length > 3) && (words[2] == "="))
            {
                if (words[3] == "new")
                {
                    string varType = RemoveBrackets(words[0].Trim()); // ignore leading tabs

                    if (words[4].StartsWith(varType))
                    {
                        // convert 'DirectoryInfo di = new DirectoryInfo("c:\\");'
                        // to 'DirectoryInfo di("c:\\");'
                        s = string.Format("{0} {1}{2}", words[0], words[1], 
                            RemoveExplicitObjectInitialization(words[4].Substring(varType.Length).Replace("()", "")));
                        for (i = 5; i < words.Length; i++)
                            s += " " + words[i];
                    }
                }
                else if (words[0].EndsWith("TimeSpan"))
                {
                    s = s.Replace("=", "(").Replace("-", ",").Replace(";", ");");
                }
            }

            // BUGBUG - make sure the '.' is for a class, not a '1.23' or "Thank you."
            // OR s.Split(' ')
            s = ReplaceDotWhenAppropriate(s);

            if (s.Contains("[] "))
                s = ConvertArraysToLists(s);

            string sTrimmed = s.Trim();

            if (sTrimmed.StartsWith("foreach"))
            {
                sourceIndex++;
                s = ConvertForEach(s, sourceLines, ref sourceIndex, enums);
            }

            if (s.Contains("ArrayList "))
                s = AddImportantComment("use generics/List<> instead of ArrayList() to work with GoNative") + "//" + s;

            if (sTrimmed.StartsWith("Console::Write"))
                s = HandleConsoleWriteStatement(s);

            if (s.Contains("Debug::Assert"))
                s = HandleDebugAssert(s);

            s = s.Replace(".Start(", ".Start( hWnd ");
            s = s.Replace("this.", "this->");
            if (s.Contains("Controls().Add(this::"))
                s = s.Replace("Controls().Add(this::", "Controls.Add(&this->").Replace("());", ");");

            // convert '12F' to just '12'
            i = s.IndexOf("F");
            while( i > -1 )
            {
                // if the previous character is numeric, then remove this 'F'
                if (char.IsNumber(s[i - 1]))
                    s = s.Remove(i, 1);
                else
                    i++;
                i = s.IndexOf("F",i);
            }

            return s;
        }

        private static string HandleDebugAssert(string s)
        {
            int start = s.IndexOf("Debug::Assert");
            int end = s.LastIndexOf(";");
            int paramStart = s.IndexOf("(", start);
            int paramEnd = s.LastIndexOf(")");

            if ( start == -1 || end == -1 || paramStart == -1 || paramEnd == -1 )
                return s;

            string p = s.Substring(paramStart+1, paramEnd - paramStart-1);

            // assume ',' does not appear in the 2nd parameter description string
            string[] parameters = p.Split(',');

            string find = s.Substring(start, end - start);
            string replace = ((parameters.Length == 1)
                                 ?
                                 string.Format( "assert( {0} )", parameters[0])
                                 :
                                 string.Format("assert(({0}) && {1} )", parameters[0], parameters[1]));

            s = s.Replace(find, replace).Replace("Debug::Assert","assert");
            return s;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="containsOpeningScope"></param>
        /// <param name="containsClosingScope"></param>
        /// <param name="containsBrackets"></param>
        /// <param name="enums"></param>
        /// <returns></returns>
        private static string PreprocessLine(string s, out bool containsOpeningScope, 
            out bool containsClosingScope, out bool containsBrackets, Dictionary<string,string> enums)
        {
            containsOpeningScope = containsClosingScope = containsBrackets = false;

            s = s.Replace("System.Windows.Forms.", "");

            // also determine if string addition is going one and expand it
            char[] chars = s.ToCharArray();

            // re-order based on string parameters before we continue pre-processing
            int startOfStringWithParameters = s.IndexOf("{0}");
            if (startOfStringWithParameters > -1)
            {
                s = PreprocessStringParameters(s, chars, startOfStringWithParameters, s.IndexOf("string.Format"));
                chars = s.ToCharArray();
            }

            bool insideComment = false;
            bool insideString = false;
            int startOfStringAddition = -1;
            Stack<int> placesToInsertFunctionCalls = new Stack<int>();
            int i;

            for( i = 0; i < chars.Length; i++ )
            {
                switch( chars[i] )
                {
                    case '/':
                        if (i > 0)
                        {
                            switch( chars[i-1] )
                            {
                                case '/':
                                    // C++ comment, done processing this line, exit the loop by adjusting 'i'
                                    i = chars.Length;
                                    break;
                                case '*':
                                    insideComment = false;
                                    break;
                            }
                        }
                        break;
                    case '*':
                        if ( ( i > 0 ) && ( chars[i-1] == '/') )
                            insideComment = true;
                        break;
                    case '{':
                        if (!containsOpeningScope)
                            containsOpeningScope = !insideComment && !insideString;
                        break;
                    case '}':
                        if (!containsClosingScope)
                            containsClosingScope = !insideComment && !insideString;
                        break;
                    case '<':
                        if (!containsBrackets)
                            containsBrackets = !insideComment && !insideString;
                        break;
                    case '+':
                        if ( (startOfStringAddition == -1) && (i < chars.Length-1))
                            if ( !insideComment && !insideString && ( chars[i+1] != '=') )
                                startOfStringAddition = i;
                        break;
                    case '"':
                        insideString = !insideString;
                        break;
                    case '.':
                        if ((i < 1) || (i >= chars.Length))
                            break;
                        if (!insideComment && !insideString)
                        {
                            if (IsLetterDigitOrParen(chars[i - 1]) && char.IsLetter(chars[i + 1]))
                            {
                                // ignore '.Key' and '.Value' as they dictionary entries that
                                // we be renamed later to local variables
                                if (StringAtIndex(chars, i, ".Key"))
                                    break;
                                if (StringAtIndex(chars, i, ".Value"))
                                    break;
                                if (EnumMatch(chars,i,enums))
                                    break;
                                if (FollowedByEquals(chars,i+1))
                                    break;

                                int k = i + 1;
                                bool missingParens = true;
                                bool notDone = true;
                                while( ( k < chars.Length) && notDone )
                                {
                                    if (!char.IsLetterOrDigit(chars[k]))
                                    {
                                        missingParens = chars[k] != '(';
                                        notDone = false;
                                    }
                                    else
                                        k++;
                                }
                                if (missingParens)
                                    placesToInsertFunctionCalls.Push(k);
                            }
                        }
                        break;
                }
            }

            bool changed = placesToInsertFunctionCalls.Count > 0;
            while (placesToInsertFunctionCalls.Count > 0)
            {
                int k = placesToInsertFunctionCalls.Pop();
                if (k <= startOfStringAddition)
                    startOfStringAddition += 2;
                s = s.Insert(k, "()");
            }
            if (changed)
                chars = s.ToCharArray();

            if ( s.Contains("\"") && ( startOfStringAddition > -1) )
            {
                // we have the first + in string addition -- we now need to work backwards to 
                // find the start of what is being added
                i = startOfStringAddition - 1;

                // skip over any spaces or tabs before the '+'
                while ((chars[i] == ' ') || (chars[i] == '\t'))
                {
                    i--;
                    if ( i < 0 )
                        break;
                }

                // we have found the word before '+'.  If it is:
                // - "a phrase in quotes" then find the starting quote
                // - 'variableName' then find the start of the variable name
                // - 'totalProfit.ToString()' then find the start of the object
                // - 'GetMeAString()' then find the start of the method name
                if( ( i >= 0 ) && ( chars[i] == '"' ) )
                {
                    // find matching '"' at the start
                    i--;
                    while (chars[i] != '"')
                    {
                        i--;
                        if (i < 0)
                            break;
                    }
                }
                else
                {
                    int parenBackwardCount = 0;
                    bool done = false;
                    while ( ( i >= 0 ) && (chars[i] != ' ') && (chars[i] != '\t'))
                    {
                        switch( chars[i])
                        {
                            case ')':
                                parenBackwardCount++;
                                break;
                            case '(':
                                done = (parenBackwardCount == 0);
                                if (done)
                                {
                                    i++;
                                    break;
                                }
                                parenBackwardCount--;
                                break;
                        }

                        if (done)
                            break;

                        i--;
                        if (i < 0)
                            break;
                    }
                }

                // wrap the first parameter in the addition in a string constructor
                if (i > -1)
                {
                    int length = startOfStringAddition - i;
                    string find = s.Substring(i, length);

                    if (!find.StartsWith("string("))
                    {
                        string replace = "string(" + find + ")";
                        s = s.Remove(i, length).Insert(i, replace);
                        s = s.Replace("string( ", "string(");
                    }
                }
            }

            return s;
        }

        private static bool FollowedByEquals(char[] chars, int i)
        {
            while( i < chars.Length)
            {
                if ( chars[i] == '=' )
                    return true;
                if ( chars[i] != ' ' && !char.IsLetterOrDigit(chars[i]) )
                    break;
                i++;
            }
            return false;
        }

        private static bool EnumMatch(char[] chars, int i, Dictionary<string,string> enums)
        {
            //foreach (string enumValue in enums)
            foreach (KeyValuePair<string,string> kvp in enums)
            {
                string enumValue = kvp.Value;
                int before = enumValue.IndexOf(".");
                if ( before <= i)
                {
                    i -= before;
                    char[] test = enumValue.ToCharArray();
                    int k;
                    for( k = 0; k < test.Length; k++,i++)
                        if ( test[k] != chars[i])
                            break;
                    if ( k == test.Length)
                        return true; // made it all the way, it is a match
                }
            }
            return false;
        }

        private static bool IsLetterDigitOrParen(char c)
        {
            return char.IsLetterOrDigit(c) || c == '(' || c == ')';
        }

        /// <summary>
        /// Return true if the specified string is found at the specified index in the char array.
        /// </summary>
        /// <param name="chars"></param>
        /// <param name="i"></param>
        /// <param name="searchFor"></param>
        /// <returns></returns>
        private static bool StringAtIndex(char[] chars, int i, string searchFor )
        {
            int charsFromTheEnd = chars.Length - i;
            if ( searchFor.Length >= charsFromTheEnd )
                return false;
            for( int k = 0; k < searchFor.Length; k++ )
                if ( chars[i+k] != searchFor[k])
                    return false;
            return true;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="chars"></param>
        /// <param name="i"></param>
        /// <param name="stringFormatIndex"></param>
        /// <returns></returns>
        private static string PreprocessStringParameters(string s, char[] chars, int i, int stringFormatIndex)
        {
            if ( stringFormatIndex != -1 )
            {
                string temp = RemoveFunctionCallWrapper(s, chars, stringFormatIndex);
                if ( !string.IsNullOrEmpty(temp))
                {
                    s = temp;
                    i -= 14; // 14 = "string.Format(".Length();
                }
            }

            int startOfParameters = s.IndexOf("\",", i);
            if ( startOfParameters == -1 )
                return s;

            startOfParameters += 2;

            bool reAddClosingParen = false;
            string[] parameters = s.Substring(startOfParameters).Trim().Split(',');
            i = parameters.Length - 1;
            int found = parameters[i].LastIndexOf(")");
            if (found == -1)
                found = parameters[i].LastIndexOf(";");
            else
                reAddClosingParen = true;
            if (found != -1)
                parameters[i] = parameters[i].Substring(0, found);
            for (int k = 0; k < parameters.Length-1; k++)
                parameters[k] = parameters[k].Trim(); // leave spacing alone on end of last parameter

            s = s.Substring(0, startOfParameters - 1);

            for(i = 0; i < parameters.Length; i++)
            {
                string find = "{" + i + "}";
                string replace = "\"+" + parameters[i] + "+\"";
                s = s.Replace(find, replace);
            }

            i = s.IndexOf("\"\"+");
            if (i != -1 )
                s = s.Remove(i, 3);
            i = s.LastIndexOf("+\"\"");
            if (i != -1)
                s = s.Remove(i, 3);

            // merge string together (w/ and w/o spaces between them)
            s = s.Replace("\"+\"", "");
            s = s.Replace("\" + \"", "");
            s = s.Replace("\"+ \"", "");
            s = s.Replace("\" +\"", "");

            return s + ( reAddClosingParen ? " );" : ";" );
        }


        /// <summary>
        /// Remove points to the start of the function/method name.  Remove it's name
        /// everything between 'index' and the opening paren, and remove the closing
        /// paren.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="chars"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static string RemoveFunctionCallWrapper(string s, char[] chars, int index)
        {
            int opening = s.IndexOf("(", index);
            if ( opening == -1 )
                return null;
            int parenCount = 0;
            int closing = opening + 1;
            bool done = false;
            while( closing < chars.Length && !done )
            {
                switch( chars[closing] )
                {
                    case '(':
                        parenCount++;
                        break;
                    case ')':
                        if (parenCount == 0)
                            done = true;
                        else
                            parenCount--;
                        break;
                }
                closing++;
            }
            if ( closing >= chars.Length )
                return null;

            s = s.Remove(closing-1, 1);
            s = s.Remove(index,opening-index+1);
            return s;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string RemoveSpacesInsideBrackets(string s)
        {
            int start = 0;
            while (start != -1)
            {
                start = s.IndexOf("<", start);
                if (start == -1)
                    break;
                int end = s.IndexOf(">", start);
                if (end == -1)
                    break;
                int length = end - start + 1;
                string sub = s.Substring(start, length);
                if (sub.Contains(" "))
                {
                    sub = sub.Replace(" ", "");
                    s = s.Remove(start, length);
                    s = s.Insert(start, sub);
                }
                start++;
            }
            return s;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string RemoveBrackets(string s)
        {
            int start = s.IndexOf("<");
            if (start > -1)
            {
                int end = s.IndexOf(">", start);
                if (end > -1)
                    s = s.Remove(start, end - start + 1);
            }
            return s;
        }



        /// <summary>
        /// Convert C#'s explicit object initialization to C++.
        /// If input is 'List<string>();' then return ';'
        /// but if input is 'List<string>(tests);' then return '(tests);'
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string RemoveExplicitObjectInitialization(string s)
        {
            s = s.Replace(" ", "");
            int start = s.IndexOf("<");
            if (start > -1)
            {
                string initializer = GetSubString(s, "(", ")", true);
                if (!string.IsNullOrEmpty(initializer))
                {
                    s = initializer + ";";
                }
                else
                {
                    int end = s.IndexOf("()", start);
                    if (end == -1)
                        end = s.IndexOf(">", start);
                    if (end > -1)
                        s = s.Remove(start, end - start + 1);
                }
            }
            return s;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string ReplaceDotWhenAppropriate(string s)
        {
            int start = s.IndexOf(".");
            int lastStart = 0;
            while (start != -1)
            {
                if (!InAComment(s, start))
                    if (!InAHardcodedString(s, start))
                        if (!FollowingAVariableName(s, start))
                            if (!AlreadyConvertedThisEntity(s, start, lastStart))
                                if ( !FollowedByEquals(s.ToCharArray(), start+1))
                                    s = s.Remove(start, 1).Insert(start, "::");
                lastStart = start;
                start = s.IndexOf(".", start + 1);
            }
            return s;
        }

        /// <summary>
        /// Need to prevent 'DateTime::Now( ).Day()' from being converted to 'DateTime::Now( )::Day()'
        /// </summary>
        /// <returns></returns>
        private static bool AlreadyConvertedThisEntity(string s, int end, int start)
        {
            if ( start == 0 )
                return false;

            char[] chars = s.ToCharArray();

            if (chars[start++] != ':')
                return false;
            if (chars[start++] != ':')
                return false;
            int parenCount = 0;
            bool inQuotes = false;
            while( start < end )
            {
                switch (chars[start])
                {
                    case '(':
                        parenCount++;
                        break;
                    case ')':
                        parenCount--;
                        if (parenCount < 0)
                            return false;
                        break;
                    case '"':
                        inQuotes = !inQuotes;
                        break;
                    case '+':
                        if (!inQuotes)
                            return false;
                        break;
                    case '-':
                        if (!inQuotes)
                            return false;
                        break;
                    case '*':
                        if (!inQuotes)
                            return false;
                        break;
                    case '/':
                        if (!inQuotes)
                            return false;
                        break;
                    case ' ':
                        if ( parenCount < 1 )
                            return false;
                        break;
                    default:
                        if ( ( parenCount < 1) && ( !char.IsLetterOrDigit(chars[start])) )
                            return false;
                        break;
                }
                start++;
            }
            return true;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="line"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static bool InAComment(string line, int index)
        {
            int cPlusPlusStyle = line.IndexOf("//");
            if (cPlusPlusStyle != -1)
                if (cPlusPlusStyle < index)
                    return true;

            int cStyleStart = line.IndexOf("/*");
            if (cStyleStart != -1)
            {
                if (cStyleStart > index)
                    return false;

                int cStyleEnd = line.IndexOf("*/");
                if (cStyleEnd == -1)
                    return true;

                if (cStyleEnd > index)
                    return true;
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="line"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static bool InAHardcodedString(string line, int index)
        {
            char[] chars = line.Substring(0, index).ToCharArray();
            int quoteCount = 0;
            foreach (char c in chars)
                if (c == '"')
                    quoteCount++;

            // return true if there is an odd number of '"' before 'index'.
            return ((quoteCount%2) != 0);
        }


        #region VariableScoping

        /// <summary>
        /// 
        /// </summary>
        public static void PopScopedVariables()
        {
            VariablesInScope.Pop();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        public static void PushScopedVariables(string s)
        {
            s = RemoveSubBlocks(s).Replace("\r", "").Replace("\t", "");
            s = RemoveComments(s);
            s = ReplaceCompletely(s, "\n\n", "\n");

            Dictionary<string, string> variables = new Dictionary<string, string>();
            // key is the variable name, value is the variable type

            Dictionary<string, string> vars = new Dictionary<string, string>();
            // key is the variable name, value is the variable that initialized it

            // now find possible variables and add them to our list
            string[] lines = s.Split('\n');

            foreach (string line in lines)
            {
                string key = string.Empty;
                string value = string.Empty;
                int i;
                s = line;
                if (!s.Contains("foreach"))
                {
                    i = s.IndexOf("(");
                    if (i != -1)
                        s = s.Substring(0, i);
                }
                string[] words = s.Split(' ');

                if (s.Contains("=") || s.Contains(" in "))
                    for (i = 0; i < words.Length; i++)
                        if ((words[i] == "=") || (words[i] == "in"))
                        {
                            key = words[i - 1].Trim();
                            if (key.Contains("["))
                            {
                                key = string.Empty;
                                break; // not a variable, perhaps assigning something to a Directionary
                            }

                            if (i < 2)
                            {
                                key = string.Empty;
                                break;
                            }

                            value = words[i - 2].Replace("(", "").Trim();

                            if (value == "var")
                                value = LookUpVariableType(words[words.Length - 1], variables);
                            if (value == "var")
                                vars[key] = words[i + 1].Replace(";", "").Replace(")", "").Trim();
                            else
                                variables[key] = value;
                            key = string.Empty;
                            continue;
                        }

                Debug.Assert(string.IsNullOrEmpty(key));
                if (s.Contains(";"))
                    for (i = 0; i < words.Length; i++)
                    {
                        if (words[i].Contains(";"))
                            key = words[i].Replace(";", "").Trim();
                        if (words[i].Contains(","))
                            key = words[i].Replace(",", "").Trim();
                        if (!string.IsNullOrEmpty(key))
                        {
                            if (string.IsNullOrEmpty(value))
                            {
                                value = i > 0 ? words[i - 1].Trim() : "type-unknown-because-of-multi-line-declaration";
                                if (value == "var")
                                    value = LookUpVariableType(words[words.Length - 1], variables);
                            }
                            variables[key] = value;
                            key = string.Empty;
                        }
                    }
            }

            // now resolve all the types of the 'var' variables that we can
            if (vars.Count > 0)
            {
                int resolvedLastPass;
                int resolved = 0;
                do
                {
                    resolvedLastPass = resolved;
                    resolved = 0;
                    List<string> keysToRemove = new List<string>();

                    foreach (KeyValuePair<string, string> v in vars)
                    {
                        if (variables.ContainsKey(v.Value))
                        {
                            resolved++;
                            variables[v.Key] = variables[v.Value];
                            keysToRemove.Add(v.Key);
                        }
                    }

                    foreach (string key in keysToRemove)
                        vars.Remove(key);
                } while ((resolved > 0) && (resolved != resolvedLastPass) && (vars.Count > 0));
            }


            // push them onto the variable queue, even if empty
            VariablesInScope.Push(variables);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="variableName"></param>
        /// <param name="localVars"></param>
        /// <returns></returns>
        private static string LookUpVariableType(string variableName, IDictionary<string, string> localVars)
        {
            variableName = variableName.Replace(";", "").Trim();
            if (localVars != null)
                if (localVars.ContainsKey(variableName))
                    return localVars[variableName];
            foreach (Dictionary<string, string> vars in VariablesInScope)
                if (vars.ContainsKey(variableName))
                    return vars[variableName];
            return "var";
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string RemoveComments(string s)
        {
            int cPlusPlusStyle = s.IndexOf("//");
            while (cPlusPlusStyle != -1)
            {
                int eol = s.IndexOf("\n", cPlusPlusStyle);
                if (eol == -1)
                    break;
                s = s.Remove(cPlusPlusStyle, eol - cPlusPlusStyle);
                cPlusPlusStyle = s.IndexOf("//");
            }

            int cStyleStart = s.IndexOf("/*");
            while (cStyleStart != -1)
            {
                int cStyleEnd = s.IndexOf("*/", cStyleStart);
                if (cStyleEnd == -1)
                    break;
                s = s.Remove(cStyleStart, cStyleEnd - cStyleStart);
                cStyleStart = s.IndexOf("/*");
            }
            return s;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="toFind"></param>
        /// <param name="toReplace"></param>
        /// <returns></returns>
        public static string ReplaceCompletely(string s, string toFind, string toReplace)
        {
            string before;
            string after = s;
            do
            {
                before = after;
                after = before.Replace(toFind, toReplace);
            } while (before != after);
            return after.StartsWith("\n") ? after.Substring(1) : after;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string RemoveSubBlocks(string s)
        {
            int startOfOurBlock = s.IndexOf("{");
            if (startOfOurBlock == -1)
                return string.Empty;

            s = s.Substring(startOfOurBlock + 1);

            int lastBlockStart = s.LastIndexOf("{");
            while (lastBlockStart > -1)
            {
                int blockEnd = s.IndexOf("}", lastBlockStart);
                if (blockEnd == -1)
                    break;

                s = s.Remove(lastBlockStart, blockEnd - lastBlockStart + 1);
                lastBlockStart = s.LastIndexOf("{");
            }
            return s;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="line"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static bool FollowingAVariableName(string line, int index)
        {
            // if 'int i = c.Length' then 'possibleVariableName' should be set to 'c'.
            string[] words = line.Substring(0, index).Replace("(", " ").Split(' ');
            string possibleVariableName = words[words.Length - 1].Trim();

            // make sure this isn't a number
            int i;
            if (Int32.TryParse(possibleVariableName, out i))
                return true; // we are not following a variable name, but we don't want to convert the '.' to '::'

            foreach (Dictionary<string, string> vars in VariablesInScope)
                if (vars.ContainsKey(possibleVariableName))
                    return true;

            return false;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ConvertUnmanagedVariablesToManagedAsNeeded(string source)
        {
            // if native types are being used in an iterative fashion then we need
            // to switch to our managed types.  Ex:
            // change 'List<int>' to 'List<Int32>'
            // change 'Dictionary<string,double>' to 'Dictionary<string,Double>'

            if (ManagedToUnmanagedLookup.Count == 0)
            {
                ManagedToUnmanagedLookup["bool"] = "Boolean";
                ManagedToUnmanagedLookup["byte"] = "Byte";
                ManagedToUnmanagedLookup["char"] = "Char";
                ManagedToUnmanagedLookup["decimal"] = "Decimal";
                ManagedToUnmanagedLookup["double"] = "Double";
                ManagedToUnmanagedLookup["float"] = "Float";
                ManagedToUnmanagedLookup["int"] = "Int32";
                ManagedToUnmanagedLookup["long"] = "Long";
                ManagedToUnmanagedLookup["sbyte"] = "Sbyte";
                ManagedToUnmanagedLookup["short"] = "Short";
                ManagedToUnmanagedLookup["uint"] = "UInt";
                ManagedToUnmanagedLookup["ulong"] = "ULong";
                ManagedToUnmanagedLookup["ushort"] = "UShort";
            }

            int start = 0;
            while (start != -1)
            {
                start = source.IndexOf("<", start);
                if (start == -1)
                    break;
                int end = source.IndexOf(">", start);
                if (end == -1)
                    break;

                start++;
                int length = end - start;
                string[] varTypes = source.Substring(start, length).Split(',');
                int i;

                StringBuilder sb = new StringBuilder();
                for (i = 0; i < varTypes.Length; i++)
                {
                    varTypes[i] = varTypes[i].Trim();

                    if (ManagedToUnmanagedLookup.ContainsKey(varTypes[i]))
                        varTypes[i] = ManagedToUnmanagedLookup[varTypes[i]];

                    sb.Append(varTypes[i]);
                    if (i < varTypes.Length - 1)
                        sb.Append(",");
                }
                source = source.Remove(start, length);
                source = source.Insert(start, sb.ToString());
                start++;
            }
            return source;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ConvertVarToCorrectVariableType(string source)
        {
            string[] lines = source.Split('\n');
            bool changed = false;
            int i;
            for (i = 0; i < lines.Length; i++)
            {
                string line = lines[i];

                if (VarComesBeforeEqual(line))
                {
                    string[] words = line.Split(' ');
                    string varType = LookUpVariableType(words[words.Length - 1], null);
                    if (string.IsNullOrEmpty(varType))
                        continue;

                    // found the variable type, now apply it
                    string varToChange = words[0].Replace("\t", "").Trim();
                    words[0] = words[0].Replace(varToChange, varType);

                    StringBuilder sb = new StringBuilder();
                    int k = 0;
                    for (; k < words.Length - 1; k++)
                        sb.Append(words[k] + " ");
                    sb.Append(words[k]);
                    lines[i] = sb.ToString();
                    changed = true;
                }
            }

            if (changed)
            {
                StringBuilder sb = new StringBuilder();
                for (i = 0; i < lines.Length; i++)
                    sb.Append(lines[i] + "\n");
                source = sb.ToString();
            }

            return source;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        private static bool VarComesBeforeEqual(string line)
        {
            int iVar = line.IndexOf("var ");
            if (iVar == -1)
                return false;
            int iEquals = line.IndexOf("=");
            return (iVar < iEquals);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="startsWith"></param>
        /// <param name="endsWith"></param>
        /// <param name="inclusive"></param>
        /// <returns></returns>
        private static string GetSubString(string s, string startsWith, string endsWith, bool inclusive)
        {
            int start = s.IndexOf(startsWith);
            if (start == -1)
                return string.Empty;
            int end = s.LastIndexOf(endsWith);
            if (end == -1)
                return string.Empty;

            int length = end - start + 1;
            if (!inclusive)
            {
                start += 1;
                length -= 2;
            }

            return s.Substring(start, length);
        }

        public static void ShowProgramInfo()
        {
            Console.WriteLine("GoNativeTranslator Version " + GoNativeTranslatorVersion);
            Console.WriteLine("Copyright (C) Jason Nottingham");
            Console.WriteLine("http://gonative.codeplex.com\n");
        }

        public static string HandlePreprocessorDirectives(string source)
        {
            const string ifTrue = "\n#if true";
            const string ifFalse = "\n#if false";

            if (source.Contains(ifTrue))
                source = source.Replace(ifTrue, "\n#if 1");

            if (source.Contains(ifFalse))
                source = source.Replace(ifFalse, "\n#if 0");

            return source;
        }

        /// <summary>
        /// Calculate SHA1 hash string (hex) for a scrubbed version of the source code passed in.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string CalculateSha1ForCode(string source)
        {
            // strip all comments and white space from the code.
            // if the user changes comments or whitespace we shouldn't count this as a change.
            // sha1 hash is used when the user recodes our translation by-hand and 
            // places it in a file to use for in-place substitutions when we do future
            // translations of the same C# source.  If the actual code changes (not
            // comments or whitespace) then we want to warn them that their translation
            // might now be out of date.

            ASCIIEncoding encoding = new ASCIIEncoding();
            SHA1 sha = new SHA1CryptoServiceProvider();
            source = StripComments(source).Replace("\t", "").Replace("\n", "").Replace("\r", "");
            byte[] data = encoding.GetBytes(source);
            byte[] hash = sha.ComputeHash(data);
            return BitConverter.ToString(hash).Replace("-", "");
        }

        public static string ReadFieldValue(string source, string header)
        {
            int i = source.IndexOf(header);
            if (i == -1)
                return string.Empty;
            i += header.Length;

            int endOfLine = source.IndexOf("\r", i);
            if (endOfLine == -1)
                endOfLine = source.IndexOf("\n", i);
            Debug.Assert(endOfLine != -1);
            if (endOfLine == -1)
                return string.Empty;

            return source.Substring(i, endOfLine - i).Trim();
        }

        public static string RemoveGlobalDirectives(string source)
        {
            int start = source.IndexOf("[global::");
            while (start != -1)
            {
                int end = source.IndexOf("\n", start);
                source = source.Remove(start, end - start);
                start = source.IndexOf("[global::");
            }
            start = source.IndexOf("#region");
            while (start != -1)
            {
                int end = source.IndexOf("\n", start);
                source = source.Remove(start, end - start);
                start = source.IndexOf("#region");
            }
            start = source.IndexOf("#endregion");
            while (start != -1)
            {
                int end = source.IndexOf("\n", start);
                source = source.Remove(start, end - start);
                start = source.IndexOf("#endregion");
            }

            /*
            const string comment =
                "/* DllImport commented-out -- make sure to statically link to this library (or load it dynamically\n";

            start = source.IndexOf("[DllImport");
            while( start != -1 )
            {
                int end = source.IndexOf(";", start);
                source = source.Insert(end + 1, "* /").Insert(start,comment);
                start = end + comment.Length + 1;
                start = source.IndexOf("[DllImport", start+1);
            }*/

            return source;
        }


        public static string FinalProcessingStep(string text)
        {
            string[][] test = {
                                new[]{"\n", "\r\n"},
                                new[]{"\r\r\n", "\r\n"},
                                new[]{"this::", "this->"},
                                new[]{"Keys::Escape()", "VK_ESCAPE"},
                                new[]{"Keys::Enter()", "VK_RETURN"},
                                new[]{"DialogResult::OK()", "IDOK"},
                                new[]{"DialogResult::Cancel()", "IDCANCEL"},
                                new[]{"[STAThread]", ""},
                                new[]{"System.ComponentModel.", ""},
                                new[]{"System.Windows.Forms.", ""},
                              };

            foreach (string[] s in test)
                text = text.Replace(s[0], s[1]);

            StringBuilder sb = new StringBuilder();
            string[] lines = text.Split('\n');
            foreach( string line in lines )
            {
                if (line.Contains("this->") && line.Contains("="))
                    sb.Append(line.Replace("()", "") + "\n");
                else
                    sb.Append(line + "\n");
            }
            text = sb.ToString();
            return text;
        }

        public static string GetDesignerFileName(string name)
        {
            int i = name.LastIndexOf(".cs");
            if (i == -1)
                return string.Empty;
            name = name.Insert(i,".Designer");
            return name;
        }
    }
}